// ------------------------------------------------------------------------
// Encoder handling
// ------------------------------------------------------------------------
#include "encoders.h"


volatile int encoders_c::DEC_movement = 0;
volatile int encoders_c::RA_movement = 0;
volatile int8_t encoders_c::RA_shaftreset = 0;
volatile int encoders_c::RA_shaftmovement = 0;
ra_axis_c* encoders_c::raAxis;
dec_axis_c* encoders_c::decAxis;

void encoders_c::begin(ra_axis_c* raObj, dec_axis_c* decObj) {
	// callback objects
	raAxis = raObj;
	decAxis = decObj;
	// PORTK (A8-A12) for reading encoders
	// set A8-12 for encoder input (set 0)
	DDRK &= B11100000;
	// pull up enoder inputs A8-A12 (set 1)
	PORTK |= B00011111;
	// turn interrupt enable bit for portk on in PCIR register
	PCICR |= (1<<PCIE2);
	// turn on A8-A11 in pinchangemask (z-index does not need interrupt)
	PCMSK2 |= B00011111;
	// turn on interrupts
	sei();
}

void encoders_c::interrupt() {
	// Lookup array to interpret encoder pin change direction
										// AB AB   desc
	static int enc_states[] = {0,	// 00 00 - no change
							  -1,	// 00 01 - B rising A low
							  1,	// 00 10 - A rising B low
							  0,	// 00 11 - invalid
							  1,	// 01 00 - B falling A low
							  0,	// 01 01 - no change
							  0,	// 01 10 - no change
							  -1,	// 01 11 - A rising B high
							  -1,	// 10 00 - A falling B low
							  0,	// 10 01 - invalid
							  0,	// 10 10 - no change
							  1,	// 10 11 - B rising A high
							  0,	// 11 00 - invalid
							  1,	// 11 01 - A falling B high
							  -1,	// 11 10 - B falling A high
							  0		// 11 11 - no change
							 }; 
	// ra encoder movement
	// -------------------
	static uint8_t old_AB_RA = ( PINK & B00000011 );
	// remember previous state Shift the bits so bits 0 & 1 are now in bits 2 & 3
	old_AB_RA <<= 2;  
	// Read the current RA encoder state into bits 0 & 1
	old_AB_RA |= ( PINK & B00000011 );  
	// 'interpet' that encoder movement from the array
	RA_movement -= ( enc_states[( old_AB_RA & 0x0F )]); 
	// do the same for the shaft position
	RA_shaftmovement -= ( enc_states[( old_AB_RA & 0x0F )]); 
	// handle the z index on RA encoder connected to D9 - no interrupt on this pin just read every RA interrupt
	static byte oldZ = ((PINK & B00010000) >> 4);
	// only want to update oldZ if RA moved - so ignore if this interrupt generated by DEC move
	// http://www.datasheetarchive.com/dataframe.php?file=DSA-335783.pdf&dir=Datasheets-17&part=E6B2-CWZ3E#
	if( (enc_states[( old_AB_RA & 0x0F )] != 0) && (oldZ !=  ((PINK & B00010000) >> 4)) ) {
		oldZ = ((PINK & B00010000) >> 4); // save change
		// went 'forwards' over z ( reset on Z falling )
		if( (oldZ == 0) &&  (enc_states[( old_AB_RA & 0x0F )] == -1) ) { 
			RA_shaftreset = -1;
			RA_shaftmovement = -1;
		}
		// went 'backwards' over z ( reset on Z rising )
		if( (oldZ == 1) &&  (enc_states[( old_AB_RA & 0x0F )] == 1) ) { 
			RA_shaftreset = 1;
			RA_shaftmovement = 1;
		}
	}
	// callback
	if(( enc_states[( old_AB_RA & 0x0F )])!=0) { 
		raAxis->priorityUpdate();
	}
	
	// dec encoder movement
	// --------------------
	static uint8_t old_AB_DEC = ( (PINK >> 2) & B00000011 );
	//remember previous state Shift the bits so bits 0 & 1 are now in bits 2 & 3
	old_AB_DEC <<= 2;  
	// Read the current DEC encoder state into bits 0 & 1
	old_AB_DEC |= ( (PINK >> 2) & B00000011 );  
	// 'interpet' that enocoder movement from the array
	DEC_movement -= ( enc_states[( old_AB_DEC & 0x0F )]); 
	// callback
	if(( enc_states[( old_AB_DEC & 0x0F )])!=0) {
		decAxis->priorityUpdate();
	}
}

int encoders_c::readRAencoderMovement() {
	int8_t returnval = RA_movement;
	RA_movement = 0;
	return returnval;
}

int encoders_c::readDECencoderMovement() {
	int8_t returnval = DEC_movement;
	DEC_movement = 0;
	return returnval;
}

int encoders_c::readRAshaftMovement() {
	int8_t returnval = RA_shaftmovement;
	RA_shaftmovement = 0;
	return returnval;
}

int8_t encoders_c::readRAshaftReset() {
	int8_t returnval = RA_shaftreset;
	RA_shaftreset = 0;
	return returnval;
}



encoders_c encoders = encoders_c();

// PORTK pin change interrupt
ISR(PCINT2_vect)
{
	encoders.interrupt();
}
